#pragma once
#include "common.hpp"
#include <fstream>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

//通用工具类
class utility
{
public:
                                                              //一般建议用vector<char>作为二进制读写的缓冲区, 彻底杜绝特殊字符问题, 但是这里还得更改每一层的缓冲区, 过于麻烦了, 有机会再实现
    static bool get_file_content(const std::string& filename, std::string& content/*输出型参数*//*vector<char>& content*/)
    {
        std::ifstream in(filename, std::ios::in | std::ios::binary); //二进制读写, 避免因为一些特殊字符("\0"等)导致读不完整
        if(in.is_open() == false)
        {
            LOG(wzx::log_level::ERROR) << "open " << filename << " fail!!!";
            return false;//打开文件失败
        }

        //设置文件输入流的位置指示器
        in.seekg(0, in.end);//将指示器设置在相对于in.end偏移0bytes的位置
        int filesize = in.tellg();
        in.seekg(0, in.beg);//同理

        content.resize(filesize);
        //直接用从基类basic_istream继承过来的方法, 以字符块形式读, 防止出现因为特殊字符导致的读不完整
        //in.read((char*)content.c_str(), filesize);//c_str() 返回的是 const char*，不能修改, 强制转换为 (char*) 是未定义行为
        in.read(content.data(), filesize);//c++17后data()方法支持返回char*
            
        //in.close();//i/ofstream对象析构会自动close(), 可以忽略此步
        return true;
    }

    static bool get_and_erase_a_line(std::string& str/*输入输出*/, std::string& out_str/*输出*/, const std::string& line_separator)
    {
        size_t line_end = str.find(line_separator);
        if(line_end == std::string::npos)
            return false;

        out_str = str.substr(0, line_end + line_separator.size());
        str.erase(0, line_end);
        return true;
    }

    static size_t get_filesize(const std::string& filename)
    {
        //法1: linux系统调用
        // struct stat file_stat;
        // if(stat(filename.c_str(), &file_stat) == -1)
        //     return -1;
        // return file_stat.st_size;

        //法2: 
        std::ifstream in(filename, std::ios::in | std::ios::binary);
        if(in.is_open() == false)
            return -1;

        in.seekg(0, in.end);
        size_t filesize = in.tellg();
        in.seekg(0, in.beg);
        return filesize;
    }

    static std::string get_Content_Type(const std::string& URI)
    {
        size_t pos = URI.rfind('.');
        if(pos == std::string::npos)
        {
            LOG(wzx::log_level::ERROR) << "get_Content_Type fail!!!";
            return "";
        }
        std::string type = URI.substr(pos);
        if(type == ".html" || type == ".htm")
            return "text/html";
        else if(type == ".jpg")
            return "image/jpeg";
        else if(type == "png")
            return "image/png";
        //else if ... 都应该设置在你的server内
        else
            return "";

    }

};